﻿using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService;

public partial class Parser
{
    private static readonly SyntaxKinds[] ProcedureKinds =
    [
        SyntaxKinds.SubKeywordToken,
        SyntaxKinds.FunctionKeywordToken,
        SyntaxKinds.DoKeywordToken,
        SyntaxKinds.WhileKeywordToken,
        SyntaxKinds.ForKeywordToken
    ];

    private bool IsSourceFileNeedUpdate(SourceTextFile source)
    {
        return source.TryGetSyntaxTreeByEntryFileName(_tree.Entry.FileName, out SyntaxTree? tree)
               || tree == null
               || tree.GetTimeStamp() < source.TimeStamp;
    }


    private SyntaxTree UpdateSourceSyntaxTree(SourceTextFile source, SyntaxTreeParseContext? context = null)
    {
        SyntaxTree updateTree = ParseTree(source, _tree.Entry, context ?? GetSyntaxTreeParseContext());
        source.UpdateSyntaxTree(_tree.Entry.FileName, updateTree);
        return updateTree;
    }


    private void UpdateFileIncludeDiagnostics(FileInclude includeNode, DiagnosticInfo[] diagnosticInfos)
    {
        DiagnosticChain bag = new();

        if (diagnosticInfos.Length > 5)
        {
            bag.Raise(DiagnosticDescriptors.TooManyErrorInTargetFile, includeNode.IncludeFileName);
            return;
        }

        // 将语法树错误添加到 #include 节点上，并添加关联文本位置
        foreach (DiagnosticInfo diag in diagnosticInfos)
        {
            bag.Raise(diag.Descriptor, includeNode.IncludeFileName, diag.MessageArgs ?? []);
        }

        _diagnostics.Raise(bag);
    }


    private static bool CanSourceFileInclude(SourceTextFile file)
    {
        return file.Type is SourceFileType.Mrs or SourceFileType.Dms;
    }


    /// <summary>
    ///     处理 #include 预处理节点
    /// </summary>
    private SyntaxTreeIncludeNode ParseSyntaxTreeInclude()
    {
        FileInclude fileIncludeNode = (FileInclude)GetCurrentNode();
        SyntaxTreeIncludeNode node = NodeFactory.CreateSyntaxTreeIncludeNode(null, fileIncludeNode);

        // 查找源文件
        // #include "PATH"
        // 此时，如果成功找到指定文件，SourceTextFile.Preprocessed 应当不是 null
        if (fileIncludeNode.Source is { } source)
        {
            // 不允许引入 .d.mrs | .m.dms | .r.dms
            // 如果有已经解析完成并且不需要更新的语法树，直接使用已有结果
            if (CanSourceFileInclude(source) && IsSourceFileNeedUpdate(source)) // 需要更新
            {
                SyntaxTree tree = UpdateSourceSyntaxTree(source);
                node.UpdateSyntaxTree(tree);
                UpdateFileIncludeDiagnostics(fileIncludeNode, tree.GetDiagnostics().ToArray());
            }
        }
        // #include RELATIVE_NAME
        else if (fileIncludeNode.IncludeFileName.IsIdentifier)
        {
            SyntaxTreeParseContext context = GetSyntaxTreeParseContext();
            int refCount = 0;
            foreach ((string targetPath, SourceTextFile includeFile) in _source.Manager.GetReferences(
                         fileIncludeNode.IncludeFileName.Text))
            {
                // 需要目标文件
                if (!targetPath.Equals(_source.FileName, StringComparison.OrdinalIgnoreCase) ||
                    !IsSourceFileNeedUpdate(includeFile))
                {
                    continue;
                }

                node.UpdateSyntaxTree(UpdateSourceSyntaxTree(includeFile, context));
                ++refCount;
            }

            // 没有任何引用文件时，报告错误
            if (refCount == 0)
            {
                Raise(DiagnosticDescriptors.IncludePathFailure, fileIncludeNode.IncludeFileName,
                    fileIncludeNode.IncludeFileName.Text);
            }
        }

        return FinishNode(node, fileIncludeNode);
    }


    /// <summary>
    ///     解析单个表达式语句
    /// </summary>
    private ExpressionStatement ParseExpressionStatement(bool fromCurrent = false)
    {
        Expression expr = fromCurrent ? ParseExpressionFromCurrent() : ParseExpression();
        ExpressionStatement stat = NodeFactory.CreateExpressionStatement(null, expr);
        return FinishNode(stat, GetStartPoint(expr));
    }


    private ExpressionStatement CreateEmptyExpressionStatement(DiagnosticDescriptor? descriptor = null,
        params object?[] args)
    {
        EmptyExpression expr = CreateEmptyExpression(descriptor, args);
        ExpressionStatement stat = NodeFactory.CreateExpressionStatement(null, expr);
        return FinishNode(stat, GetStartPoint(expr));
    }


    /// <summary>
    ///     Option 语句，需要当前节点是 <see cref="SyntaxKinds.OptionKeywordToken" />
    /// </summary>
    /// <returns></returns>
    private OptionStatement ParseOptionStatement()
    {
        SyntaxToken optionKeyword = GetToken();
        SyntaxToken? settingKeyword = Expect([
            SyntaxKinds.ImplicitKeywordToken,
            SyntaxKinds.ExplicitKeywordToken, SyntaxKinds.GlobalVariablesKeywordToken
        ]);
        OptionStatement stat = NodeFactory.CreateOptionStatement(null, optionKeyword, settingKeyword);

        if (stat.IsGlobalVariables)
        {
            _state.IsOptionGlobalVariables = true;
        }
        else
        {
            _state.IsOptionImplicit = stat.IsImplicit;
        }

        return FinishNode(stat, GetStartPoint(optionKeyword));
    }


    /// <summary>
    ///     Exit语句，Exit后可以是过程名：Sub，Function，For，While，Do
    /// </summary>
    /// <returns></returns>
    private ExitStatement ParseExit()
    {
        SyntaxToken exit = GetToken();
        SyntaxToken? procedure = null;

        if (!IsLineEnd())
        {
            SourceNode procedureSource = Next();
            if (procedureSource.IsOneOfNode(ProcedureKinds))
            {
                procedure = GetToken();
            }
            else
            {
                Raise(DiagnosticDescriptors.InvalidProcedureName, procedureSource);
            }
        }

        ExitStatement statement = NodeFactory.CreateExitStatement(null, exit, procedure);
        return FinishNode(statement, GetStartPoint(exit));
    }


    /// <summary>
    ///     Goto 语句，需要当前节点是 <see cref="SyntaxKinds.GotoKeywordToken" />
    /// </summary>
    private GotoStatement ParseGotoStatement()
    {
        SyntaxToken keyword = GetToken();
        GotoStatement stat;

        if (TryParse(SyntaxKinds.Integer))
        {
            IntegerLiteral number = ParseInteger();
            // 0
            if (number.Value != 0)
            {
                Raise(DiagnosticDescriptors.UnexpectedToken,
                    number, "0");
            }

            stat = NodeFactory.CreateGotoStatement(null, keyword, number);
        }
        else
        {
            stat = NodeFactory.CreateGotoStatement(null, keyword, ExpectIdentifier());
        }

        return FinishNode(stat, GetStartPoint(keyword));
    }


    /// <summary>
    ///     Resume 语句，需要当前节点是 <see cref="SyntaxKinds.ResumeKeywordToken" />
    /// </summary>
    private ResumeStatement ParseResumeStatement()
    {
        SyntaxToken keywordToken = GetToken();
        SyntaxToken? nextKeywordToken = null;
        if (TryParse(SyntaxKinds.NextKeywordToken))
        {
            nextKeywordToken = GetToken();
        }

        ResumeStatement stat = NodeFactory.CreateResumeStatement(null, keywordToken, nextKeywordToken);
        return FinishNode(stat, GetStartPoint(keywordToken));
    }


    /// <summary>
    ///     On Error 语句，需要当前节点是 <see cref="SyntaxKinds.OnKeywordToken" />
    /// </summary>
    /// <returns></returns>
    private OnErrorStatement ParseOnErrorStatement()
    {
        SyntaxToken onKeywordToken = GetToken();
        SyntaxToken errorToken = Expect(SyntaxKinds.ErrorKeywordToken);

        GotoStatement? gotoStat = null;
        ResumeStatement? resumeStat = null;

        if (TryParse([SyntaxKinds.GotoKeywordToken, SyntaxKinds.ResumeKeywordToken], out SourceNode? node))
        {
            if (node.IsNode(SyntaxKinds.GotoKeywordToken))
            {
                gotoStat = ParseGotoStatement();
            }
            else
            {
                resumeStat = ParseResumeStatement();
            }
        }

        OnErrorStatement stat = NodeFactory.CreateOnErrorStatement(null, onKeywordToken,
            errorToken);

        if (gotoStat != null)
        {
            stat.Update(gotoStat);
        }

        if (resumeStat != null)
        {
            stat.Update(resumeStat);
        }

        if (gotoStat == null && resumeStat == null)
        {
            Raise(DiagnosticDescriptors.UnexpectedToken, errorToken.End,
                errorToken.End + 1, "Goto 或 Resume");
        }

        return FinishNode(stat, GetStartPoint(onKeywordToken));
    }


    /// <summary>
    ///     数字区间表达式，Left To Right
    /// </summary>
    /// <param name="parent">父节点</param>
    private RangeExpression ParseRangeExpression(SyntaxNode? parent)
    {
        Expression leftBound = ParseExpression(allowAssignment: false);
        SyntaxToken toKeywordToken = Expect(SyntaxKinds.ToKeywordToken);
        // 遇到换行时结束
        Expression rightBound = EmptyExpression.Default;
        if (!IsLineEnd())
        {
            rightBound = ParseExpression(allowAssignment: false);
        }

        RangeExpression expression = NodeFactory.CreateRangeExpression(leftBound, toKeywordToken, rightBound, parent);
        return FinishNode(expression, GetStartPoint(leftBound));
    }


    /// <summary>
    ///     If 条件语句
    /// </summary>
    /// <remarks>
    ///     <list type="number">
    ///         <item><term>单行表达式</term>If ConditionExpression Then Expression [Else Expression]</item>
    ///         <item>
    ///             <term>多行表达式</term>
    ///             <code>
    /// If ConditionExpression Then
    ///     [Statements]
    /// [ElseIf ConditionExpression Then
    ///     [Statements]]
    /// [Else
    ///     [Statements]]
    /// End If
    ///             </code>
    ///         </item>
    ///     </list>
    /// </remarks>
    private IfStatement ParseIfStatement()
    {
        SyntaxToken keyword = GetToken();
        Expression? condition = null;
        SyntaxToken? thenKeywordToken = null;

        // 不是 Else 关键字，期望表达式
        if (!keyword.IsNode(SyntaxKinds.ElseKeywordToken))
        {
            condition = ParseExpression(true, false);
            thenKeywordToken = Expect(SyntaxKinds.ThenKeywordToken);
        }

        IfStatement ifStat = NodeFactory.CreateIfStatement(null, keyword, condition, thenKeywordToken);
        bool isSingleLine = !IsLineEnd();
        _blockStack.Push(ifStat);

        // 单行表达式
        if (isSingleLine)
        {
            ifStat.Update(ParseBlock([SyntaxKinds.ElseKeywordToken], true));
            // Else
            if (CurrentIs(SyntaxKinds.ElseKeywordToken))
            {
                SyntaxToken elseKw = GetToken();
                IfStatement elseStat = NodeFactory.CreateIfStatement(
                    null, elseKw, null, null);
                elseStat.Update(ParseBlock([SyntaxKinds.ElseKeywordToken], true));
                FinishNode(elseStat, GetStartPoint(elseKw));
                ifStat.Update(elseStat);
            }
        }
        // 多行表达式
        else
        {
            ifStat.Update(ParseBlock([
                SyntaxKinds.ElseIfKeywordToken, SyntaxKinds.ElseKeywordToken, SyntaxKinds.EndKeywordToken
            ]));
            // ElseIf | Else
            if (CurrentIsOneOf(SyntaxKinds.ElseIfKeywordToken, SyntaxKinds.ElseKeywordToken))
            {
                ifStat.Update(ParseIfStatement());
            }
            // End
            else
            {
                ExpectContinuousTokens([SyntaxKinds.EndKeywordToken, SyntaxKinds.IfKeywordToken], true);
            }
        }

        _blockStack.Pop();
        return FinishNode(ifStat, GetStartPoint(keyword));
    }


    /// <summary>
    ///     For 循环语句
    /// </summary>
    /// <remarks>
    ///     <code>
    /// For counter = LowerBound To UpperBound [ Step Integer]
    ///     [Statements]
    /// Next
    /// </code>
    /// </remarks>
    private ForStatement ParseForStatement(SyntaxToken forKeywordToken)
    {
        Identifier counter = Identifier.Default;
        SyntaxToken equalToken = SyntaxToken.Default;
        RangeExpression range = RangeExpression.Empty;
        SyntaxToken? stepKeywordToken = null;
        IntegerLiteral? stepInteger = null;

        // counter
        if (!IsLineEnd())
        {
            Next();
            counter = ParseIdentifierName();
        }

        // =
        if (!IsLineEnd())
        {
            equalToken = Expect(SyntaxKinds.EqualToken);
        }

        // LeftBound
        if (!IsLineEnd())
        {
            range = ParseRangeExpression(null);
        }
        
        // step
        if (!IsLineEnd() && TryParse(SyntaxKinds.StepKeywordToken))
        {
            stepKeywordToken = GetToken();
            Expression stepExpr = ParseExpression(false, false);
            if (!NodeConverter.TryConvertNegativeInteger(stepExpr, out stepInteger))
            {
                Raise(DiagnosticDescriptors.UnexpectedToken, stepExpr, "整数");
            }
        }

        ForStatement forStat = NodeFactory.CreateForStatement(null, forKeywordToken);
        forStat.Update(counter, equalToken, range);

        if (stepKeywordToken != null && stepInteger != null)
        {
            forStat.Update(stepKeywordToken, stepInteger);
        }

        // body
        _blockStack.Push(forStat);
        forStat.Update(ParseBlock([SyntaxKinds.NextKeywordToken]));
        _blockStack.Pop();

        SyntaxToken? nextKeywordToken = ExpectCurrent(SyntaxKinds.NextKeywordToken,
            true);

        if (nextKeywordToken != null)
        {
            forStat.Update(nextKeywordToken);
        }

        return FinishNode(forStat, GetStartPoint(forKeywordToken));
    }


    /// <summary>
    ///     解析 For Each 循环语句
    /// </summary>
    /// <remarks>
    ///     <code>
    /// For Each element In groupExpression
    ///     [Statements]
    /// Next
    /// </code>
    /// </remarks>
    private ForEachStatement ParseForEachStatement(SyntaxToken forKeywordToken)
    {
        SyntaxToken eachKeywordToken = GetToken();

        Identifier element = Identifier.Default;
        SyntaxToken inKeywordToken = SyntaxToken.Default;
        Expression groupExpression = EmptyExpression.Default;

        // element
        if (!IsLineEnd())
        {
            element = ExpectIdentifier();
        }

        // in
        if (!IsLineEnd())
        {
            inKeywordToken = Expect(SyntaxKinds.InKeywordToken);
        }

        // group
        if (!IsLineEnd())
        {
            groupExpression = ParseExpression();
        }

        ForEachStatement forEachStat = NodeFactory.CreateForEachStatement(null,
            forKeywordToken, eachKeywordToken);

        forEachStat.Update(element, inKeywordToken, groupExpression);

        // body
        _blockStack.Push(forEachStat);
        forEachStat.Update(ParseBlock([SyntaxKinds.NextKeywordToken]));
        _blockStack.Pop();

        // Next
        SyntaxToken? nextKeywordToken = ExpectCurrent(SyntaxKinds.NextKeywordToken,
            true);

        if (nextKeywordToken != null)
        {
            forEachStat.UpdateFrom(nextKeywordToken);
        }

        return FinishNode(forEachStat, GetStartPoint(forKeywordToken));
    }


    /// <summary>
    ///     解析 For 关键字开头的语句， For 或者 For Each 语句。
    /// </summary>
    private Statement ParseForLikeStatement()
    {
        SyntaxToken forKeywordToken = GetToken();

        // 后面换行 -> ForStatement
        if (IsLineEnd())
        {
            return ParseForStatement(forKeywordToken);
        }

        if (TryParse(SyntaxKinds.EachKeywordToken))
        {
            return ParseForEachStatement(forKeywordToken);
        }

        return ParseForStatement(forKeywordToken);
    }


    /// <summary>
    ///     While 循环语句
    /// </summary>
    /// <remarks>
    ///     <code>
    /// While conditionExpression
    ///     [Statements]
    /// End While
    /// </code>
    /// </remarks>
    private WhileStatement ParseWhileStatement()
    {
        SyntaxToken whileKeywordToken = GetToken();
        Expression? condition = null;

        if (!IsLineEnd())
        {
            condition = ParseExpression(true, false);
        }

        // while statement
        WhileStatement whileStat = NodeFactory.CreateWhileStatement(null, whileKeywordToken, condition);
        // body
        _blockStack.Push(whileStat);
        whileStat.Update(ParseBlock([SyntaxKinds.EndKeywordToken]));
        _blockStack.Pop();
        // End While
        if (CurrentIs(SyntaxKinds.EndKeywordToken))
        {
            ExpectContinuousTokens(
                [SyntaxKinds.EndKeywordToken, SyntaxKinds.WhileKeywordToken], true);
        }

        return FinishNode(whileStat, GetStartPoint(whileKeywordToken));
    }


    /// <summary>
    ///     Do 语句
    /// </summary>
    /// <remarks>
    ///     <code>
    /// Do
    ///     [Statements]
    /// Loop [While | Until] ConditionExpression
    /// </code>
    ///     或
    ///     <code>
    /// Do [While | Until] ConditionExpression
    ///     [Statements]
    /// Loop
    /// </code>
    /// </remarks>
    private DoStatement ParseDoStatement()
    {
        SyntaxToken doKeywordToken = GetToken();
        DoStatement doStat = NodeFactory.CreateDoStatement(null, doKeywordToken);
        bool headCondition = false;
        SyntaxToken? whileOrUntilKeywordToken = null;
        Expression? condition = null;
        // 前置条件
        if (TryParse([SyntaxKinds.WhileKeywordToken, SyntaxKinds.UntilKeywordToken], out _))
        {
            whileOrUntilKeywordToken = GetToken();

            if (!IsLineEnd())
            {
                condition = ParseExpression();
            }

            headCondition = true;
        }

        // body
        _blockStack.Push(doStat);
        doStat.Update(ParseBlock([SyntaxKinds.LoopKeywordToken]));
        _blockStack.Pop();
        // Loop
        SyntaxToken? loopKeywordToken = ExpectCurrent(SyntaxKinds.LoopKeywordToken);
        // Until | While
        if (headCondition)
        {
            if (loopKeywordToken != null && whileOrUntilKeywordToken != null && condition != null)
            {
                doStat.Update(loopKeywordToken, whileOrUntilKeywordToken, condition);
            }

            return FinishNode(doStat, GetStartPoint(doKeywordToken));
        }

        whileOrUntilKeywordToken =
            Expect([SyntaxKinds.WhileKeywordToken, SyntaxKinds.UntilKeywordToken]);

        if (!IsLineEnd())
        {
            condition = ParseExpression();
        }

        if (loopKeywordToken != null && whileOrUntilKeywordToken != null && condition != null)
        {
            doStat.Update(loopKeywordToken, whileOrUntilKeywordToken, condition);
        }

        return FinishNode(doStat, GetStartPoint(doKeywordToken));
    }


    /// <summary>
    ///     Select Case 分支语句
    /// </summary>
    /// <remarks>
    ///     <code>
    /// Case [Else | Comparisons]
    ///     [Body]
    /// </code>
    /// </remarks>
    private SelectCaseClause ParseSelectCaseClause()
    {
        SyntaxToken caseKeywordToken = GetToken();
        SyntaxToken? elseKeywordToken = Optional(SyntaxKinds.ElseKeywordToken);
        SelectCaseClause clause = NodeFactory.CreateSelectCaseClause(null, caseKeywordToken, elseKeywordToken);

        if (elseKeywordToken == null)
        {
            bool isEmpty = true;
            while (!IsLineEnd())
            {
                if (!isEmpty)
                {
                    Expect(SyntaxKinds.CommaToken);
                }

                clause.AddCondition(ParseSelectCaseComparision());
                isEmpty = false;
            }
        }

        // body
        _blockStack.Push(clause);
        clause.Update(ParseBlock([SyntaxKinds.CaseKeywordToken, SyntaxKinds.EndKeywordToken]));
        _blockStack.Pop();

        return FinishNode(clause, GetStartPoint(caseKeywordToken));
    }


    /// <summary>
    ///     Select Case 语句
    /// </summary>
    /// <remarks>
    ///     <code>
    /// Select Case ConditionExpression
    ///     [Clauses]
    /// End Select
    /// </code>
    /// </remarks>
    private SelectStatement ParseSelectStatement()
    {
        SyntaxToken selectKeywordToken = GetToken();
        SyntaxToken caseKeywordToken = Expect(SyntaxKinds.CaseKeywordToken);
        SelectStatement selectStat = NodeFactory.CreateSelectStatement(null, selectKeywordToken, caseKeywordToken);
        Expression condition = ParseExpression(true, false);

        selectStat.Update(condition);

        Next();
        _blockStack.Push(selectStat);

        while (CurrentIs(SyntaxKinds.CaseKeywordToken))
        {
            selectStat.AddClause(ParseSelectCaseClause());
        }

        _blockStack.Pop();

        ExpectContinuousTokens([SyntaxKinds.EndKeywordToken, SyntaxKinds.SelectKeywordToken], true);
        return FinishNode(selectStat, GetStartPoint(selectKeywordToken));
    }


    /// <summary>
    ///     With 语句
    /// </summary>
    /// <remarks>
    ///     <code>
    /// With Expression
    ///     [Statements]
    /// End With
    /// </code>
    /// </remarks>
    private WithStatement ParseWithStatement()
    {
        SyntaxToken withKeywordToken = GetToken();
        Expression? expression = null;
        if (!IsLineEnd())
        {
            expression = ParseExpression();
        }

        WithStatement stat = NodeFactory.CreateWithStatement(null, withKeywordToken, expression);

        _withStack.Push(stat);
        // body
        _blockStack.Push(stat);
        stat.Update(ParseBlock([SyntaxKinds.EndKeywordToken]));
        _blockStack.Pop();
        _withStack.Pop();

        ExpectContinuousTokens(
            [SyntaxKinds.EndKeywordToken, SyntaxKinds.WithKeywordToken], true);
        return FinishNode(stat, GetStartPoint(withKeywordToken));
    }


    /// <summary>
    ///     解析Section语句块，需要当前节点是<see cref="SyntaxKinds.SectionKeywordToken" />。
    /// </summary>
    /// <returns></returns>
    private SectionStatement ParseSection()
    {
        SyntaxToken sectionKeywordToken = GetToken();
        SyntaxToken label = Expect(SyntaxKinds.Identifier);
        SectionStatement section = NodeFactory.CreateSectionStatement(null,
            sectionKeywordToken, NodeConverter.ToIdentifier(label));

        _section = section;
        section.Update(ParseBlock([SyntaxKinds.EndKeywordToken]));
        ExpectContinuousTokens(
            [SyntaxKinds.EndKeywordToken, SyntaxKinds.SectionKeywordToken], true);
        _section = null;

        return FinishNode(section, GetStartPoint(sectionKeywordToken));
    }


    private Statement ParseScriptStatement()
    {
        SourceNode node = GetCurrentNode();

        switch (node.Kind)
        {
            // #include
            case SyntaxKinds.FileInclude:
                return ParseSyntaxTreeInclude();

            // Optional
            case SyntaxKinds.OptionKeywordToken:
                return ParseOptionStatement();

            // Exit
            case SyntaxKinds.ExitKeywordToken:
                return ParseExit();

            // Goto
            case SyntaxKinds.GotoKeywordToken:
                return ParseGotoStatement();

            // On
            case SyntaxKinds.OnKeywordToken:
                return ParseOnErrorStatement();

            // Resume
            case SyntaxKinds.ResumeKeywordToken:
                return ParseResumeStatement();

            // If
            case SyntaxKinds.IfKeywordToken:
                return ParseIfStatement();

            // For
            case SyntaxKinds.ForKeywordToken:
                return ParseForLikeStatement();

            // While
            case SyntaxKinds.WhileKeywordToken:
                return ParseWhileStatement();

            // Do
            case SyntaxKinds.DoKeywordToken:
                return ParseDoStatement();

            // Select
            case SyntaxKinds.SelectKeywordToken:
                return ParseSelectStatement();

            // With
            case SyntaxKinds.WithKeywordToken:
                return ParseWithStatement();

            // Section
            case SyntaxKinds.SectionKeywordToken:
                return ParseSection();

            // Dim
            case SyntaxKinds.DimKeywordToken:
                return ParseDimStatement();

            // Const
            case SyntaxKinds.ConstKeywordToken:
                return ParseConstantDeclaration();

            // Function | Sub
            case SyntaxKinds.FunctionKeywordToken:
            case SyntaxKinds.SubKeywordToken:
                return ParseFunctionDeclaration();

            // Identifier:
            case SyntaxKinds.Identifier:
                if (TryParse(SyntaxKinds.ColonToken))
                {
                    return ParseLabel(NodeFactory.CreateIdentifier(node));
                }

                break;
        }

        return ParseExpressionStatement(true);
    }


    private Statement ParseMetadata()
    {
        SourceNode node = GetCurrentNode();
        // #include
        return node.Kind == SyntaxKinds.FileInclude ? ParseSyntaxTreeInclude() : ParseMetadataStatement();
    }


    private Statement ParseStatement()
    {
        // 元数据上下文
        if (_state.GetKeywordContexts(KeywordContexts.Metadata))
        {
            return ParseMetadata();
        }

        // DMS上下文
        if (_state.GetKeywordContexts(KeywordContexts.Dms))
        {
            return ParseDmsStatement();
        }

        // Declare上下文
        return _state.GetKeywordContexts(KeywordContexts.Declaration)
            ? ParseDeclareStatement()
            : ParseScriptStatement();
    }


    private Block ParseBlock(SyntaxKinds[]? stopTokens = null, bool singleLine = false)
    {
        SyntaxKinds[] ends = [SyntaxKinds.Eof, .. stopTokens ?? []];
        SyntaxPoint start = GetCurrentEndPoint();
        Block block = NodeFactory.CreateBlock(null);

        while (!Eof() && (!singleLine || !IsLineEnd()))
        {
            SourceNode next = Next();

            if (next.IsOneOfNode(ends) || next.IsEof)
            {
                break;
            }

            if (block.IsEmpty && !singleLine)
            {
                CheckPrecedingLinebreak();
            }

            Statement stat = ParseStatement();

            // 跳过空语句或错误语句
            if (stat.IsEmpty)
            {
                continue;
            }

            block.AddStatement(stat);

            // 检查是否可作为跳转标签
            if (stat.Is<LabelDeclaration>(SyntaxKinds.Label, out LabelDeclaration? labelDecl))
            {
                block.AddLabel(labelDecl);
            }
        }

        return FinishNode(block, start, GetCurrentStartPoint());
    }


    /// <summary>
    ///     读取语法节点列表，中间可以有固定的分隔符
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="endTokens">结尾的Token类型，结束时当前的Token类型应当是此列表中的一个或EOF</param>
    /// <param name="separatorToken">
    ///     分隔符类型，如果忽略分隔符，设置此参数是<see cref="SyntaxKinds.Unknown" />，
    ///     此时，列表中的语句将强制需要换行
    /// </param>
    /// <param name="parser">读取区间内单个语句的回调函数，需要此函数从当前Token开始</param>
    /// <param name="onParsed">在<paramref name="parser" />调用结束后的回调函数</param>
    /// <param name="allowLastSeparatorToken">是否允许在列表的最后一个元素后带有分隔符</param>
    /// <param name="allowSeparatorNewline">分隔符前是否允许换行</param>
    /// <param name="maxSize">期望读取的最大数量</param>
    private void ParseBlockWithSeparator<T>(SyntaxKinds[] endTokens, SyntaxKinds separatorToken,
        Func<T> parser, Action<T> onParsed, bool allowLastSeparatorToken = false,
        bool allowSeparatorNewline = false, int maxSize = 0) where T : SyntaxNode
    {
        SyntaxKinds[] sepOrEndKinds = separatorToken == SyntaxKinds.Unknown
            ? [SyntaxKinds.Eof, .. endTokens]
            : [separatorToken, SyntaxKinds.Eof, .. endTokens];

        int count = 0;
        SyntaxToken? sepOrEndToken = null;

        while (!Eof())
        {
            SourceNode next = Next();

            if (next.IsOneOfNode(endTokens))
            {
                if (sepOrEndToken != null && !allowLastSeparatorToken)
                {
                    Raise(DiagnosticDescriptors.ExcessToken, sepOrEndToken,
                        SyntaxFacts.ConvertTokenToString(sepOrEndToken.Kind));
                }

                break;
            }

            // 如果忽略了分隔符，则强制需要换行
            if (separatorToken == SyntaxKinds.Unknown && !next.HasPrecedingLinebreak)
            {
                Raise(DiagnosticDescriptors.NeedLinebreak, next.Span);
            }

            onParsed(parser());
            ++count;

            // 到结尾时，因为后续需要调用 Next 方法，此处需要跳出
            if (Eof())
            {
                break;
            }

            // 如果设置了最大数量，此处期望结束符号并跳出
            if (maxSize > 0 && count >= maxSize)
            {
                Expect(endTokens);
                break;
            }

            // 可能是结束 Token 或 分隔符 Token
            // 如果分隔符是 Unknown，视为没有分隔符，此时，只检查后续节点
            // 是否是结束节点即可。
            if (separatorToken == SyntaxKinds.Unknown)
            {
                sepOrEndToken = TryParse(() =>
                {
                    SourceNode nextToken = Next();
                    return nextToken.IsOneOfNode(endTokens)
                        ? NodeFactory.CreateSyntaxToken(nextToken)
                        : null;
                });
            }
            else
            {
                sepOrEndToken = Expect(sepOrEndKinds, allowSeparatorNewline);
            }

            // 遇到结束符，跳出
            if (sepOrEndToken != null && sepOrEndToken.IsOneOfNode(endTokens))
            {
                break;
            }

            if (sepOrEndToken != null && !allowSeparatorNewline &&
                sepOrEndToken.HasPrecedingLinebreak)
            {
                Raise(DiagnosticDescriptors.UnexpectedLinefeed, sepOrEndToken);
            }
        }

        // 如果到文件末尾还没有遇到结束符号，报告错误
        if (Eof())
        {
            Raise(DiagnosticDescriptors.UnexpectedToken,
                string.Join(" 或 ", endTokens.Select(SyntaxFacts.ConvertTokenToString)));
        }
    }
    

    private record DmsSectionWithDescriptionStartInfo(
        SyntaxToken Keyword,
        Identifier Name,
        StringLiteral? Description);


    /// <summary>
    ///     解析可选的文本参数，如果当前是','，才会往后读取。
    /// </summary>
    private StringLiteral? ParseOptionalText()
    {
        SyntaxToken? comma = Optional(SyntaxKinds.CommaToken);
        if (!TryParse([SyntaxKinds.String, SyntaxKinds.Identifier], out SourceNode? token))
        {
            return null;
        }

        if (comma == null)
        {
            RaiseAt(DiagnosticDescriptors.UnexpectedToken,
                token.Start, ",");
        }

        return ParseStringLike();
    }

    /// <summary>
    ///     解析DMS带有命名和描述的语句块开头，Keyword (ID[, "Description"])
    /// </summary>
    private DmsSectionWithDescriptionStartInfo StartDmsSectionWithDescription()
    {
        SyntaxToken keyword = GetToken();
        Identifier id = Identifier.Default;
        // (
        Expect(SyntaxKinds.LeftParenthesisToken);
        // ID
        if (TryParse(IdentifierOrStringKinds, out _, true))
        {
            id = ParseIdentifierLike();
        }

        // [,]
        StringLiteral? desc = ParseOptionalText();
        // )
        Expect(SyntaxKinds.RightParenthesisToken);
        return new DmsSectionWithDescriptionStartInfo(keyword, id, desc);
    }


    /// <summary>
    ///     解析DMS文件中的 Event 语句块，需要当前节点是 <see cref="SyntaxKinds.EventKeywordToken" />
    /// </summary>
    private EventSection ParseEventSection()
    {
        DmsSectionWithDescriptionStartInfo info = StartDmsSectionWithDescription();

        if (info.Name.Value.Equals("OnNextCase", StringComparison.OrdinalIgnoreCase))
        {
            _state.IsOnNextCaseEvent = true;
        }

        EventSection section = NodeFactory.CreateEventSection(null,
            info.Keyword, info.Name, info.Description);
        _eventSection = section;
        _state.SetKeywordContexts(KeywordContexts.Mrs);
        section.Update(ParseBlock([SyntaxKinds.EndKeywordToken]));
        ExpectContinuousTokens([SyntaxKinds.EndKeywordToken, SyntaxKinds.EventKeywordToken], true);
        _state.SetKeywordContexts(KeywordContexts.Dms);
        _state.IsOnNextCaseEvent = false;
        _eventSection = null;
        return FinishNode(section, GetStartPoint(info.Keyword));
    }


    /// <summary>
    ///     解析DMS中的Routing语句块，需要当前节点是<see cref="SyntaxKinds.RoutingKeywordToken" />
    /// </summary>
    private RoutingSection ParseRoutingSection()
    {
        SyntaxToken routingKeywordToken = GetToken();
        // (
        Expect(SyntaxKinds.LeftParenthesisToken);
        // Context
        StringLiteral? context = null;
        if (TryParse([SyntaxKinds.String, SyntaxKinds.Identifier], out _))
        {
            context = ParseStringLike();
        }

        // )
        Expect(SyntaxKinds.RightParenthesisToken);

        RoutingSection routingSection = NodeFactory.CreateRoutingSection(null, routingKeywordToken, context);
        _state.SetKeywordContexts(KeywordContexts.Mrs);
        routingSection.Update(ParseBlock([SyntaxKinds.EndKeywordToken]));
        _state.SetKeywordContexts(KeywordContexts.Dms);
        ExpectContinuousTokens([SyntaxKinds.EndKeywordToken, SyntaxKinds.RoutingKeywordToken], true);
        return FinishNode(routingSection, GetStartPoint(routingKeywordToken));
    }


    /// <summary>
    ///     解析DMS语句块中的属性赋值语句，[PropertyName = Value]。
    ///     需要当前节点是属性名，中间不能换行并且需要单独在一行。
    ///     此处的属性名不能使用字符串。
    /// </summary>
    private DmsProperty ParseDmsProperty()
    {
        // 需要单行
        if (!_state.HasPrecedingLinebreak())
        {
            Raise(DiagnosticDescriptors.NeedLinebreak);
        }

        // ID
        Identifier id = ParseIdentifierName();
        SyntaxToken eq = Expect(SyntaxKinds.EqualToken);
        Expression value = EmptyExpression.Default;
        // 不可换行
        if (!SyntaxToken.IsNullOrEmpty(eq) && !IsLineEnd())
        {
            value = ParseExpression();
        }

        DmsProperty property = NodeFactory.CreateDMSProperty(null, id, value);
        return FinishNode(property, GetStartPoint(id));
    }


    private DmsProperty?[] ParseDmsPropertySection(string[] keys, string sectionName)
    {
        DmsProperty?[] result = new DmsProperty?[keys.Length];
        ParseBlockWithSeparator([SyntaxKinds.EndKeywordToken], SyntaxKinds.Unknown,
            ParseDmsProperty,
            prop =>
            {
                if (Identifier.IsDefaultOrEmpty(prop.NameIdentifier))
                {
                    return;
                }

                int index = Array.FindIndex(keys, x =>
                    x.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
                if (index >= 0)
                {
                    result[index] = prop;
                }
                else
                {
                    Raise(DiagnosticDescriptors.UnknownSectionProperty,
                        prop.NameIdentifier, sectionName, prop.Name);
                }
            });

        return result;
    }


    /// <summary>
    ///     解析DMS中的Job语句块，需要当前节点是<see cref="SyntaxKinds.JobKeywordToken" />。
    /// </summary>
    private JobSection ParseJobSection()
    {
        DmsSectionWithDescriptionStartInfo info = StartDmsSectionWithDescription();
        DmsProperty?[] properties = ParseDmsPropertySection(["TempDirectory"], "Job");
        // End Job
        ExpectContinuousTokens([SyntaxKinds.EndKeywordToken, SyntaxKinds.JobKeywordToken], true);
        JobSection job = NodeFactory.CreateJobSection(null, info.Keyword, info.Name, info.Description,
            properties[0]);
        return FinishNode(job, GetStartPoint(info.Keyword));
    }


    /// <summary>
    ///     解析DMS中的GlobalSQLVariables语句块，需要当前节点是
    ///     <see cref="SyntaxKinds.GlobalSqlVariablesKeywordToken" />。
    /// </summary>
    private GlobalSqlVariablesSection ParseGlobalSqlVariablesSection()
    {
        DmsSectionWithDescriptionStartInfo info = StartDmsSectionWithDescription();
        DmsProperty?[] properties = ParseDmsPropertySection(["ConnectionString", "SelectQuery"],
            "GlobalSQLVariables");
        ExpectContinuousTokens(
            [SyntaxKinds.EndKeywordToken, SyntaxKinds.GlobalSqlVariablesKeywordToken],
            true);
        GlobalSqlVariablesSection section = NodeFactory.CreateGlobalSqlVariablesSection(null, info.Keyword,
            info.Name, info.Description, properties[0], properties[1]);
        return FinishNode(section, GetStartPoint(info.Keyword));
    }

    private static readonly string[] InputDataSourcePropertyNames =
    [
        "ConnectionString",
        "SelectQuery",
        "UpdateQuery",
        "JoinKey",
        "JoinType",
        "UseInputAsOutput",
        "JoinKeySorted"
    ];


    /// <summary>
    ///     解析DMS中的InputDataSource语句块，需要当前节点是
    ///     <see cref="SyntaxKinds.InputDataSourceKeywordToken" />。
    /// </summary>
    private InputDataSourceSection ParseInputDataSourceSection()
    {
        DmsSectionWithDescriptionStartInfo info = StartDmsSectionWithDescription();
        DmsProperty?[] properties = ParseDmsPropertySection(InputDataSourcePropertyNames,
            "InputDataSource");
        ExpectContinuousTokens(
            [SyntaxKinds.EndKeywordToken, SyntaxKinds.InputDataSourceKeywordToken],
            true);
        InputDataSourceSection section = NodeFactory.CreateInputDataSourceSection(null, info.Keyword,
            info.Name, info.Description);
        section.Update(properties[0], properties[1], properties[2], properties[3],
            properties[4], properties[5], properties[6]);
        return FinishNode(section, GetStartPoint(info.Keyword));
    }

    private static readonly string[] OutputDataSourcePropertyNames =
    [
        "UseInputAsOutput",
        "ConnectionString",
        "MetaDataOutputName",
        "UpdateQuery",
        "TableOutputName",
        "VariableOrder"
    ];


    /// <summary>
    ///     解析DMS中的OutputDataSource语句块，需要当前节点是
    ///     <see cref="SyntaxKinds.OutputDataSourceKeywordToken" />。
    /// </summary>
    private OutputDataSourceSection ParseOutputDataSourceSection()
    {
        DmsSectionWithDescriptionStartInfo info = StartDmsSectionWithDescription();
        DmsProperty?[] properties = ParseDmsPropertySection(OutputDataSourcePropertyNames,
            "OutputDataSource");
        ExpectContinuousTokens(
            [SyntaxKinds.EndKeywordToken, SyntaxKinds.OutputDataSourceKeywordToken],
            true);
        OutputDataSourceSection section = NodeFactory.CreateOutputDataSourceSection(null, info.Keyword,
            info.Name, info.Description);
        section.Update(properties[0], properties[1], properties[2], properties[3],
            properties[4], properties[5]);
        return FinishNode(section, GetStartPoint(info.Keyword));
    }


    private static readonly string[] LoggingPropertyNames =
    [
        "Group",
        "Path",
        "Alias",
        "FileSize"
    ];


    /// <summary>
    ///     解析DMS中的Logging语句块，需要当前节点是
    ///     <see cref="SyntaxKinds.LoggingKeywordToken" />。
    /// </summary>
    private LoggingSection ParseLoggingSection()
    {
        DmsSectionWithDescriptionStartInfo info = StartDmsSectionWithDescription();
        DmsProperty?[] properties = ParseDmsPropertySection(LoggingPropertyNames, "Logging");
        ExpectContinuousTokens(
            [SyntaxKinds.EndKeywordToken, SyntaxKinds.LoggingKeywordToken],
            true);
        LoggingSection section = NodeFactory.CreateLoggingSection(null, info.Keyword,
            info.Name, info.Description, properties[0], properties[1], properties[2],
            properties[3]);
        return FinishNode(section, GetStartPoint(info.Keyword));
    }


    /// <summary>
    ///     解析DMS中的Metadata语句块，需要当前节点是
    ///     <see cref="SyntaxKinds.MetadataKeywordToken" />。
    ///     Metadata [(language [, context [, label type] [, data source]])]
    /// </summary>
    private MetadataSection ParseMetadataSection()
    {
        SyntaxToken metadataKeywordToken = GetToken();
        // (
        Expect(SyntaxKinds.LeftParenthesisToken);
        // Language
        StringLiteral? lang = null;
        if (TryParse(IdentifierOrStringKinds, out _, allowNewLine: true))
        {
            lang = ParseContinuousTokenAsString(SyntaxKinds.CommaToken, SyntaxKinds.RightParenthesisToken);
        }

        // Context
        // [, context]
        StringLiteral? context = ParseOptionalText();
        // [, label type]
        StringLiteral? labelType = ParseOptionalText();
        // [, data source]
        StringLiteral? dataSource = ParseOptionalText();
        // )
        Expect(SyntaxKinds.RightParenthesisToken);

        MetadataSection section = NodeFactory.CreateMetadataSection(null, metadataKeywordToken,
            lang, context, labelType, dataSource);
        _state.SetPunctuationContexts(PunctuationContexts.Metadata);
        _state.SetKeywordContexts(KeywordContexts.Metadata);
        section.Update(ParseBlock([SyntaxKinds.EndKeywordToken]));
        _state.SetPunctuationContexts(PunctuationContexts.Script);
        _state.SetKeywordContexts(KeywordContexts.Dms);
        ExpectContinuousTokens([SyntaxKinds.EndKeywordToken, SyntaxKinds.MetadataKeywordToken], true);
        return FinishNode(section, GetStartPoint(metadataKeywordToken));
    }


    private Statement ParseDmsStatement()
    {
        SourceNode node = GetCurrentNode();
        // #include
        if (node.Kind == SyntaxKinds.FileInclude)
        {
            return ParseSyntaxTreeInclude();
        }

        return node.Kind switch
        {
            SyntaxKinds.JobKeywordToken => ParseJobSection(),
            SyntaxKinds.LoggingKeywordToken => ParseLoggingSection(),
            SyntaxKinds.GlobalSqlVariablesKeywordToken =>
                ParseGlobalSqlVariablesSection(),
            SyntaxKinds.InputDataSourceKeywordToken =>
                ParseInputDataSourceSection(),
            SyntaxKinds.OutputDataSourceKeywordToken =>
                ParseOutputDataSourceSection(),
            SyntaxKinds.EventKeywordToken => ParseEventSection(),
            SyntaxKinds.MetadataKeywordToken => ParseMetadataSection(),
            SyntaxKinds.RoutingKeywordToken => ParseRoutingSection(),
            _ => CreateEmptyExpressionStatement(DiagnosticDescriptors.InvalidToken)
        };
    }

}